home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / WINGs / wtextfield.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-02-29  |  37.4 KB  |  1,462 lines

  1.  
  2.  
  3.  
  4.  
  5. #include "WINGsP.h"
  6.  
  7. #include <X11/keysym.h>
  8. #include <X11/Xatom.h>
  9.  
  10. #include <ctype.h>
  11.  
  12. #define CURSOR_BLINK_ON_DELAY    600
  13. #define CURSOR_BLINK_OFF_DELAY    300
  14.  
  15.  
  16.  
  17. char *WMTextDidChangeNotification = "WMTextDidChangeNotification";
  18. char *WMTextDidBeginEditingNotification = "WMTextDidBeginEditingNotification";
  19. char *WMTextDidEndEditingNotification = "WMTextDidEndEditingNotification";
  20.  
  21.  
  22. typedef struct W_TextField {
  23.     W_Class widgetClass;
  24.     W_View *view;
  25.  
  26. #if 0
  27.     struct W_TextField *nextField;     /* next textfield in the chain */
  28.     struct W_TextField *prevField;
  29. #endif
  30.  
  31.     char *text;
  32.     int textLen;               /* size of text */
  33.     int bufferSize;               /* memory allocated for text */
  34.  
  35.     int viewPosition;               /* position of text being shown */
  36.  
  37.     int cursorPosition;               /* position of the insertion cursor */
  38.  
  39.     short usableWidth;
  40.     short offsetWidth;               /* offset of text from border */
  41.  
  42.     WMRange selection;
  43.  
  44.     WMFont *font;
  45.  
  46.     WMTextFieldDelegate *delegate;
  47.  
  48. #if 0
  49.     WMHandlerID    timerID;           /* for cursor blinking */
  50. #endif
  51.     struct {
  52.     WMAlignment alignment:2;
  53.  
  54.     unsigned int bordered:1;
  55.  
  56.     unsigned int beveled:1;
  57.  
  58.     unsigned int enabled:1;
  59.  
  60.     unsigned int focused:1;
  61.  
  62.     unsigned int cursorOn:1;
  63.  
  64.     unsigned int secure:1;           /* password entry style */
  65.  
  66.     unsigned int pointerGrabbed:1;
  67.  
  68.     /**/
  69.     unsigned int notIllegalMovement:1;
  70.     } flags;
  71. } TextField;
  72.  
  73.  
  74. #define NOTIFY(T,C,N,A)    { WMNotification *notif = WMCreateNotification(N,T,A);\
  75.             if ((T)->delegate && (T)->delegate->C)\
  76.                 (*(T)->delegate->C)((T)->delegate,notif);\
  77.             WMPostNotification(notif);\
  78.             WMReleaseNotification(notif);}
  79.  
  80.  
  81. #define MIN_TEXT_BUFFER        2
  82. #define TEXT_BUFFER_INCR    8
  83.  
  84.  
  85. #define WM_EMACSKEYMASK   ControlMask
  86.  
  87. #define WM_EMACSKEY_LEFT  XK_b
  88. #define WM_EMACSKEY_RIGHT XK_f
  89. #define WM_EMACSKEY_HOME  XK_a
  90. #define WM_EMACSKEY_END   XK_e
  91. #define WM_EMACSKEY_BS    XK_h
  92. #define WM_EMACSKEY_DEL   XK_d
  93.  
  94.  
  95.  
  96. #define DEFAULT_WIDTH        60
  97. #define DEFAULT_HEIGHT        20
  98. #define DEFAULT_BORDERED    True
  99. #define DEFAULT_ALIGNMENT    WALeft
  100.  
  101.  
  102.  
  103. static void destroyTextField(TextField *tPtr);
  104. static void paintTextField(TextField *tPtr);
  105.  
  106. static void handleEvents(XEvent *event, void *data);
  107. static void handleTextFieldActionEvents(XEvent *event, void *data);
  108. static void didResizeTextField();
  109.  
  110. struct W_ViewDelegate _TextFieldViewDelegate = {
  111.     NULL,
  112.     NULL,
  113.     didResizeTextField,
  114.     NULL,
  115.     NULL
  116. };
  117.  
  118.  
  119. #define TEXT_WIDTH(tPtr, start)    (WMWidthOfString((tPtr)->font, \
  120.            &((tPtr)->text[(start)]), (tPtr)->textLen - (start) + 1))
  121.  
  122. #define TEXT_WIDTH2(tPtr, start, end) (WMWidthOfString((tPtr)->font, \
  123.            &((tPtr)->text[(start)]), (end) - (start) + 1))
  124.  
  125.  
  126. static void
  127. normalizeRange(TextField *tPtr, WMRange *range)
  128. {
  129.     if (range->position < 0 && range->count < 0)
  130.         range->count = 0;
  131.  
  132.     if (range->count == 0) {
  133.         /*range->position = 0; why is this?*/
  134.     return;
  135.     }
  136.     
  137.     /* (1,-2) ~> (0,1) ; (1,-1) ~> (0,1) ; (2,-1) ~> (1,1) */
  138.     if (range->count < 0) { /* && range->position >= 0 */
  139.     if (range->position + range->count < 0) {
  140.         range->count = range->position;
  141.         range->position = 0;
  142.     } else {
  143.         range->count = -range->count;
  144.             range->position -= range->count;
  145.     }
  146.     /* (-2,1) ~> (0,0) ; (-1,1) ~> (0,0) ; (-1,2) ~> (0,1) */
  147.     } else if (range->position < 0) { /* && range->count > 0 */
  148.         if (range->position + range->count < 0) {
  149.         range->position = range->count = 0;
  150.     } else {
  151.         range->count += range->position;
  152.         range->position = 0;
  153.     }
  154.     }
  155.     
  156.     if (range->position + range->count > tPtr->textLen)
  157.         range->count = tPtr->textLen - range->position;
  158. }
  159.  
  160. static void
  161. memmv(char *dest, char *src, int size)
  162. {
  163.     int i;
  164.     
  165.     if (dest > src) {
  166.     for (i=size-1; i>=0; i--) {
  167.         dest[i] = src[i];
  168.     }
  169.     } else if (dest < src) {
  170.     for (i=0; i<size; i++) {
  171.         dest[i] = src[i];
  172.     }
  173.     }
  174. }
  175.  
  176.  
  177. static int
  178. incrToFit(TextField *tPtr)
  179. {
  180.     int vp = tPtr->viewPosition;
  181.  
  182.     while (TEXT_WIDTH(tPtr, tPtr->viewPosition) > tPtr->usableWidth) {
  183.     tPtr->viewPosition++;
  184.     }
  185.     return vp!=tPtr->viewPosition;
  186. }
  187.  
  188.  
  189. static int
  190. incrToFit2(TextField *tPtr)
  191. {
  192.     int vp = tPtr->viewPosition;
  193.     while (TEXT_WIDTH2(tPtr, tPtr->viewPosition, tPtr->cursorPosition) 
  194.        >= tPtr->usableWidth)
  195.     tPtr->viewPosition++;
  196.  
  197.     
  198.     return vp!=tPtr->viewPosition;
  199. }
  200.  
  201.  
  202. static void
  203. decrToFit(TextField *tPtr)
  204. {
  205.     while (TEXT_WIDTH(tPtr, tPtr->viewPosition-1) < tPtr->usableWidth
  206.        && tPtr->viewPosition>0)
  207.     tPtr->viewPosition--;
  208. }
  209.  
  210. #undef TEXT_WIDTH
  211. #undef TEXT_WIDTH2
  212.  
  213. static Bool
  214. requestHandler(WMWidget *w, Atom selection, Atom target, Atom *type,
  215.            void **value, unsigned *length, int *format) 
  216. {
  217.     TextField *tPtr = w;
  218.     int count;
  219.     Display *dpy = tPtr->view->screen->display;
  220.     Atom _TARGETS;
  221.     char *text;
  222.     text = XGetAtomName(tPtr->view->screen->display,target);
  223.     XFree(text);
  224.     text = XGetAtomName(tPtr->view->screen->display,selection);
  225.     XFree(text);
  226.  
  227.     *format = 32;
  228.     *length = 0;
  229.     *value = NULL;
  230.     count = tPtr->selection.count < 0
  231.         ? tPtr->selection.position + tPtr->selection.count
  232.         : tPtr->selection.position;
  233.  
  234.     if (target == XA_STRING ||
  235.             target == XInternAtom(dpy, "TEXT", False) ||
  236.             target == XInternAtom(dpy, "COMPOUND_TEXT", False)) {
  237.         *value = wstrdup(&(tPtr->text[count]));
  238.         *length = abs(tPtr->selection.count);
  239.         *format = 8;
  240.         *type = target;
  241.         return True;
  242.     }
  243.     
  244.     _TARGETS = XInternAtom(dpy, "TARGETS", False);
  245.     if (target == _TARGETS) {
  246.         int *ptr;
  247.  
  248.         *length = 4;
  249.         ptr = *value = (char *) wmalloc(4 * sizeof(Atom));
  250.         ptr[0] = _TARGETS;
  251.         ptr[1] = XA_STRING;
  252.         ptr[2] = XInternAtom(dpy, "TEXT", False);
  253.         ptr[3] = XInternAtom(dpy, "COMPOUND_TEXT", False);
  254.         *type = target;
  255.         return True;
  256.     }
  257.     /*
  258.     *target = XA_PRIMARY;
  259.     */
  260.     return False;
  261.  
  262. }
  263.  
  264.  
  265. static void
  266. lostHandler(WMWidget *w, Atom selection)
  267. {
  268.     TextField *tPtr = (WMTextField*)w;
  269.  
  270.     tPtr->selection.count = 0;
  271.     paintTextField(tPtr);
  272. }
  273.  
  274. static void
  275. _notification(void *observerData, WMNotification *notification)
  276. {
  277.     WMTextField *to = (WMTextField*)observerData;
  278.     WMTextField *tw = (WMTextField*)WMGetNotificationClientData(notification);
  279.     if (to != tw) lostHandler(to, 0);
  280. }
  281.  
  282. WMTextField*
  283. WMCreateTextField(WMWidget *parent)
  284. {
  285.     TextField *tPtr;
  286.  
  287.     tPtr = wmalloc(sizeof(TextField));
  288.     memset(tPtr, 0, sizeof(TextField));
  289.  
  290.     tPtr->widgetClass = WC_TextField;
  291.     
  292.     tPtr->view = W_CreateView(W_VIEW(parent));
  293.     if (!tPtr->view) {
  294.     wfree(tPtr);
  295.     return NULL;
  296.     }
  297.     tPtr->view->self = tPtr;
  298.  
  299.     tPtr->view->delegate = &_TextFieldViewDelegate;
  300.  
  301.     tPtr->view->attribFlags |= CWCursor;
  302.     tPtr->view->attribs.cursor = tPtr->view->screen->textCursor;
  303.     
  304.     W_SetViewBackgroundColor(tPtr->view, tPtr->view->screen->white);
  305.     
  306.     tPtr->text = wmalloc(MIN_TEXT_BUFFER);
  307.     tPtr->text[0] = 0;
  308.     tPtr->textLen = 0;
  309.     tPtr->bufferSize = MIN_TEXT_BUFFER;
  310.  
  311.     tPtr->flags.enabled = 1;
  312.     
  313.     WMCreateEventHandler(tPtr->view, ExposureMask|StructureNotifyMask
  314.              |FocusChangeMask, handleEvents, tPtr);
  315.  
  316.     tPtr->font = WMRetainFont(tPtr->view->screen->normalFont);
  317.  
  318.     tPtr->flags.bordered = DEFAULT_BORDERED;
  319.     tPtr->flags.beveled = True;
  320.     tPtr->flags.alignment = DEFAULT_ALIGNMENT;
  321.     tPtr->offsetWidth = 
  322.     WMAX((tPtr->view->size.height - WMFontHeight(tPtr->font))/2, 1);
  323.  
  324.     W_ResizeView(tPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
  325.  
  326.     WMCreateEventHandler(tPtr->view, EnterWindowMask|LeaveWindowMask
  327.              |ButtonReleaseMask|ButtonPressMask|KeyPressMask|Button1MotionMask,
  328.              handleTextFieldActionEvents, tPtr);
  329.     
  330.     WMCreateSelectionHandler(tPtr, XA_PRIMARY, CurrentTime, requestHandler,
  331.              lostHandler, NULL);
  332.     WMAddNotificationObserver(_notification, tPtr, "_lostOwnership", tPtr);
  333.  
  334.  
  335.     tPtr->flags.cursorOn = 1;
  336.  
  337.     return tPtr;
  338. }
  339.  
  340.  
  341. void
  342. WMSetTextFieldDelegate(WMTextField *tPtr, WMTextFieldDelegate *delegate)
  343. {
  344.     CHECK_CLASS(tPtr, WC_TextField);
  345.     
  346.     tPtr->delegate = delegate;
  347. }
  348.  
  349.  
  350. void
  351. WMInsertTextFieldText(WMTextField *tPtr, char *text, int position)
  352. {
  353.     int len;
  354.  
  355.     CHECK_CLASS(tPtr, WC_TextField);
  356.     
  357.     if (!text)
  358.     return;
  359.     
  360.     len = strlen(text);
  361.  
  362.     /* check if buffer will hold the text */
  363.     if (len + tPtr->textLen >= tPtr->bufferSize) {
  364.     tPtr->bufferSize = tPtr->textLen + len + TEXT_BUFFER_INCR;
  365.     tPtr->text = wrealloc(tPtr->text, tPtr->bufferSize);
  366.     }
  367.     
  368.     if (position < 0 || position >= tPtr->textLen) {
  369.     /* append the text at the end */
  370.     strcat(tPtr->text, text);
  371.     
  372.     incrToFit(tPtr);
  373.  
  374.     tPtr->textLen += len;
  375.     tPtr->cursorPosition += len;
  376.     } else {
  377.     /* insert text at position */ 
  378.     memmv(&(tPtr->text[position+len]), &(tPtr->text[position]),
  379.                 tPtr->textLen-position+1);
  380.  
  381.     memcpy(&(tPtr->text[position]), text, len);
  382.  
  383.     tPtr->textLen += len;
  384.     if (position >= tPtr->cursorPosition) {
  385.         tPtr->cursorPosition += len;
  386.         incrToFit2(tPtr);
  387.     } else {
  388.         incrToFit(tPtr);
  389.     }
  390.     }
  391.  
  392.     paintTextField(tPtr);
  393. }
  394.  
  395. void
  396. WMDeleteTextFieldRange(WMTextField *tPtr, WMRange range)
  397. {
  398.     CHECK_CLASS(tPtr, WC_TextField);
  399.  
  400.     normalizeRange(tPtr, &range);
  401.  
  402.     if (!range.count)
  403.         return;
  404.     
  405.     memmv(&(tPtr->text[range.position]), &(tPtr->text[range.position+range.count]),
  406.             tPtr->textLen - (range.position+range.count) + 1);
  407.  
  408.     tPtr->textLen -= range.count;
  409.  
  410.     /* try to keep cursorPosition at the same place */
  411.     tPtr->viewPosition -= range.count;
  412.     if (tPtr->viewPosition < 0)
  413.         tPtr->viewPosition = 0;
  414.     tPtr->cursorPosition = range.position;
  415.     
  416.     decrToFit(tPtr);
  417.  
  418.     paintTextField(tPtr);
  419. }
  420.  
  421.  
  422.  
  423. char*
  424. WMGetTextFieldText(WMTextField *tPtr)
  425. {
  426.     CHECK_CLASS(tPtr, WC_TextField);
  427.         
  428.     return wstrdup(tPtr->text);
  429. }
  430.  
  431.  
  432. void
  433. WMSetTextFieldText(WMTextField *tPtr, char *text)
  434. {
  435.     CHECK_CLASS(tPtr, WC_TextField);
  436.     
  437.     if ((text && strcmp(tPtr->text, text) == 0) ||
  438.         (!text && tPtr->textLen == 0))
  439.         return;
  440.  
  441.     if (text==NULL) {
  442.     tPtr->text[0] = 0;
  443.     tPtr->textLen = 0;
  444.     } else {
  445.     tPtr->textLen = strlen(text);
  446.     
  447.     if (tPtr->textLen >= tPtr->bufferSize) {
  448.         tPtr->bufferSize = tPtr->textLen + TEXT_BUFFER_INCR;
  449.         tPtr->text = wrealloc(tPtr->text, tPtr->bufferSize);
  450.     }
  451.     strcpy(tPtr->text, text);
  452.     }
  453.  
  454.     tPtr->cursorPosition = tPtr->selection.position = tPtr->textLen;
  455.     tPtr->viewPosition = 0;
  456.     tPtr->selection.count = 0;
  457.     
  458.     if (tPtr->view->flags.realized)
  459.     paintTextField(tPtr);
  460. }
  461.  
  462.  
  463. void
  464. WMSetTextFieldAlignment(WMTextField *tPtr, WMAlignment alignment)
  465. {
  466.     CHECK_CLASS(tPtr, WC_TextField);
  467.     
  468.     tPtr->flags.alignment = alignment;
  469.     
  470.     if (alignment!=WALeft) {
  471.     wwarning("only left alignment is supported in textfields");
  472.     return;
  473.     }
  474.     
  475.     if (tPtr->view->flags.realized) {
  476.     paintTextField(tPtr);
  477.     }
  478. }
  479.  
  480.  
  481. void
  482. WMSetTextFieldBordered(WMTextField *tPtr, Bool bordered)
  483. {
  484.     CHECK_CLASS(tPtr, WC_TextField);
  485.     
  486.     tPtr->flags.bordered = bordered;
  487.  
  488.     if (tPtr->view->flags.realized) {
  489.     paintTextField(tPtr);
  490.     }
  491. }
  492.  
  493.  
  494. void
  495. WMSetTextFieldBeveled(WMTextField *tPtr, Bool flag)
  496. {
  497.     CHECK_CLASS(tPtr, WC_TextField);
  498.     
  499.     tPtr->flags.beveled = flag;
  500.  
  501.     if (tPtr->view->flags.realized) {
  502.     paintTextField(tPtr);
  503.     }
  504. }
  505.  
  506.  
  507.  
  508. void
  509. WMSetTextFieldSecure(WMTextField *tPtr, Bool flag)
  510. {
  511.     CHECK_CLASS(tPtr, WC_TextField);
  512.     
  513.     tPtr->flags.secure = flag;
  514.     
  515.     if (tPtr->view->flags.realized) {
  516.     paintTextField(tPtr);
  517.     }    
  518. }
  519.  
  520.  
  521. Bool
  522. WMGetTextFieldEditable(WMTextField *tPtr)
  523. {
  524.     CHECK_CLASS(tPtr, WC_TextField);
  525.     
  526.     return tPtr->flags.enabled;
  527. }
  528.  
  529.  
  530. void
  531. WMSetTextFieldEditable(WMTextField *tPtr, Bool flag)
  532. {
  533.     CHECK_CLASS(tPtr, WC_TextField);
  534.     
  535.     tPtr->flags.enabled = flag;
  536.     
  537.     if (tPtr->view->flags.realized) {
  538.     paintTextField(tPtr);
  539.     }
  540. }
  541.  
  542.  
  543. void
  544. WMSelectTextFieldRange(WMTextField *tPtr, WMRange range)
  545. {
  546.     CHECK_CLASS(tPtr, WC_TextField);
  547.     
  548.     if (tPtr->flags.enabled) {
  549.         normalizeRange(tPtr, &range);
  550.  
  551.         tPtr->selection = range;
  552.  
  553.         tPtr->cursorPosition = range.position + range.count;
  554.  
  555.         if (tPtr->view->flags.realized) {
  556.             paintTextField(tPtr);
  557.         }
  558.     }
  559. }
  560.  
  561.  
  562. void
  563. WMSetTextFieldCursorPosition(WMTextField *tPtr, unsigned int position)
  564. {
  565.     CHECK_CLASS(tPtr, WC_TextField);
  566.     
  567.     if (tPtr->flags.enabled) {
  568.         if (position > tPtr->textLen)
  569.             position = tPtr->textLen;
  570.  
  571.         tPtr->cursorPosition = position;
  572.         if (tPtr->view->flags.realized) {
  573.             paintTextField(tPtr);
  574.         }
  575.     }
  576. }
  577.  
  578.  
  579. void
  580. WMSetTextFieldNextTextField(WMTextField *tPtr, WMTextField *next)
  581. {
  582.     CHECK_CLASS(tPtr, WC_TextField);
  583.     if (next == NULL) {
  584.         if (tPtr->view->nextFocusChain)
  585.             tPtr->view->nextFocusChain->prevFocusChain = NULL;
  586.         tPtr->view->nextFocusChain = NULL;
  587.         return;
  588.     }
  589.  
  590.     CHECK_CLASS(next, WC_TextField);
  591.  
  592.     if (tPtr->view->nextFocusChain)
  593.         tPtr->view->nextFocusChain->prevFocusChain = NULL;
  594.     if (next->view->prevFocusChain)
  595.         next->view->prevFocusChain->nextFocusChain = NULL;
  596.  
  597.     tPtr->view->nextFocusChain = next->view;
  598.     next->view->prevFocusChain = tPtr->view;
  599. }
  600.  
  601.  
  602. void
  603. WMSetTextFieldPrevTextField(WMTextField *tPtr, WMTextField *prev)
  604. {
  605.     CHECK_CLASS(tPtr, WC_TextField);
  606.     if (prev == NULL) {
  607.         if (tPtr->view->prevFocusChain)
  608.             tPtr->view->prevFocusChain->nextFocusChain = NULL;
  609.         tPtr->view->prevFocusChain = NULL;
  610.         return;
  611.     }
  612.  
  613.     CHECK_CLASS(prev, WC_TextField);
  614.  
  615.     if (tPtr->view->prevFocusChain)
  616.         tPtr->view->prevFocusChain->nextFocusChain = NULL;
  617.     if (prev->view->nextFocusChain)
  618.         prev->view->nextFocusChain->prevFocusChain = NULL;
  619.  
  620.     tPtr->view->prevFocusChain = prev->view;
  621.     prev->view->nextFocusChain = tPtr->view;
  622. }
  623.  
  624.  
  625. void 
  626. WMSetTextFieldFont(WMTextField *tPtr, WMFont *font)
  627. {
  628.     CHECK_CLASS(tPtr, WC_TextField);
  629.     
  630.     if (tPtr->font)
  631.     WMReleaseFont(tPtr->font);
  632.     tPtr->font = WMRetainFont(font);
  633.   
  634.     tPtr->offsetWidth = 
  635.     WMAX((tPtr->view->size.height - WMFontHeight(tPtr->font))/2, 1);
  636.  
  637.     if (tPtr->view->flags.realized) {
  638.     paintTextField(tPtr);
  639.     }
  640. }
  641.  
  642.  
  643.  
  644. WMFont*
  645. WMGetTextFieldFont(WMTextField *tPtr)
  646. {
  647.     return tPtr->font;
  648. }
  649.  
  650.  
  651. static void 
  652. didResizeTextField(W_ViewDelegate *self, WMView *view)
  653. {
  654.     WMTextField *tPtr = (WMTextField*)view->self;
  655.  
  656.     tPtr->offsetWidth = 
  657.     WMAX((tPtr->view->size.height - WMFontHeight(tPtr->font))/2, 1);
  658.  
  659.     tPtr->usableWidth = tPtr->view->size.width - 2*tPtr->offsetWidth + 2;
  660. }
  661.  
  662.  
  663. static char*
  664. makeHiddenString(int length)
  665. {
  666.     char *data = wmalloc(length+1);
  667.  
  668.     memset(data, '*', length);
  669.     data[length] = '\0';
  670.  
  671.     return data;
  672. }
  673.  
  674.  
  675. static void
  676. paintCursor(TextField *tPtr)
  677. {
  678.     int cx;
  679.     WMScreen *screen = tPtr->view->screen;
  680.     int textWidth;
  681.     char *text;
  682.  
  683.     if (tPtr->flags.secure)
  684.         text = makeHiddenString(strlen(tPtr->text));
  685.     else
  686.         text = tPtr->text;
  687.  
  688.     cx = WMWidthOfString(tPtr->font, &(text[tPtr->viewPosition]),
  689.              tPtr->cursorPosition-tPtr->viewPosition);
  690.  
  691.     switch (tPtr->flags.alignment) {
  692.      case WARight:
  693.     textWidth = WMWidthOfString(tPtr->font, text, tPtr->textLen);
  694.     if (textWidth < tPtr->usableWidth)
  695.         cx += tPtr->offsetWidth + tPtr->usableWidth - textWidth + 1;
  696.     else
  697.         cx += tPtr->offsetWidth + 1;
  698.     break;
  699.      case WALeft:
  700.     cx += tPtr->offsetWidth + 1;
  701.     break;
  702.      case WAJustified:
  703.     /* not supported */
  704.      case WACenter:
  705.     textWidth = WMWidthOfString(tPtr->font, text, tPtr->textLen);
  706.     if (textWidth < tPtr->usableWidth)
  707.         cx += tPtr->offsetWidth + (tPtr->usableWidth-textWidth)/2;
  708.     else
  709.         cx += tPtr->offsetWidth;
  710.     break;
  711.     }
  712.     /*
  713.     XDrawRectangle(screen->display, tPtr->view->window, screen->xorGC,
  714.            cx, tPtr->offsetWidth, 1,
  715.            tPtr->view->size.height - 2*tPtr->offsetWidth - 1);
  716.     printf("%d %d\n",cx,tPtr->cursorPosition);
  717.      */
  718.     XDrawLine(screen->display, tPtr->view->window, screen->xorGC,
  719.           cx, tPtr->offsetWidth, cx,
  720.           tPtr->view->size.height - tPtr->offsetWidth - 1);
  721.  
  722.     if (tPtr->flags.secure)
  723.         wfree(text);
  724. }
  725.  
  726.  
  727.  
  728. static void
  729. drawRelief(WMView *view, Bool beveled)
  730. {
  731.     WMScreen *scr = view->screen;
  732.     Display *dpy = scr->display;
  733.     GC wgc;
  734.     GC lgc;
  735.     GC dgc;
  736.     int width = view->size.width;
  737.     int height = view->size.height;
  738.     
  739.     dgc = WMColorGC(scr->darkGray);
  740.  
  741.     if (!beveled) {
  742.     XDrawRectangle(dpy, view->window, dgc, 0, 0, width-1, height-1);
  743.  
  744.     return;
  745.     }
  746.     wgc = WMColorGC(scr->white);
  747.     lgc = WMColorGC(scr->gray);
  748.  
  749.     /* top left */
  750.     XDrawLine(dpy, view->window, dgc, 0, 0, width-1, 0);
  751.     XDrawLine(dpy, view->window, dgc, 0, 1, width-2, 1);
  752.     
  753.     XDrawLine(dpy, view->window, dgc, 0, 0, 0, height-2);
  754.     XDrawLine(dpy, view->window, dgc, 1, 0, 1, height-3);
  755.     
  756.     /* bottom right */
  757.     XDrawLine(dpy, view->window, wgc, 0, height-1, width-1, height-1);
  758.     XDrawLine(dpy, view->window, lgc, 1, height-2, width-2, height-2);
  759.  
  760.     XDrawLine(dpy, view->window, wgc, width-1, 0, width-1, height-1);
  761.     XDrawLine(dpy, view->window, lgc, width-2, 1, width-2, height-3);
  762. }
  763.  
  764.  
  765. static void
  766. paintTextField(TextField *tPtr)
  767. {
  768.     W_Screen *screen = tPtr->view->screen;
  769.     W_View *view = tPtr->view;
  770.     W_View viewbuffer;
  771.     int tx, ty, tw, th;
  772.     int rx;
  773.     int bd;
  774.     int totalWidth;
  775.     char *text;
  776.     Pixmap drawbuffer;
  777.  
  778.     
  779.     if (!view->flags.realized || !view->flags.mapped)
  780.     return;
  781.  
  782.     if (!tPtr->flags.bordered) {
  783.     bd = 0;
  784.     } else {
  785.     bd = 2;
  786.     }
  787.  
  788.     if (tPtr->flags.secure) {
  789.         text = makeHiddenString(strlen(tPtr->text));
  790.     } else {
  791.         text = tPtr->text;
  792.     }
  793.  
  794.     totalWidth = tPtr->view->size.width - 2*bd;
  795.     
  796.     drawbuffer = XCreatePixmap(screen->display, view->window,
  797.             view->size.width, view->size.height, screen->depth);
  798.     XFillRectangle(screen->display, drawbuffer, WMColorGC(screen->white),
  799.             0,0, view->size.width,view->size.height);
  800.     /* this is quite dirty */
  801.     viewbuffer.screen = view->screen;
  802.     viewbuffer.size = view->size;
  803.     viewbuffer.window = drawbuffer;
  804.  
  805.  
  806.     if (tPtr->textLen > 0) {
  807.         tw = WMWidthOfString(tPtr->font, &(text[tPtr->viewPosition]),
  808.                  tPtr->textLen - tPtr->viewPosition);
  809.     
  810.     th = WMFontHeight(tPtr->font);
  811.  
  812.     ty = tPtr->offsetWidth;
  813.     switch (tPtr->flags.alignment) {
  814.      case WALeft:
  815.         tx = tPtr->offsetWidth + 1;
  816.         if (tw < tPtr->usableWidth)
  817.         XFillRectangle(screen->display, drawbuffer,
  818.                    WMColorGC(screen->white),
  819.                    bd+tw,bd, totalWidth-tw,view->size.height-2*bd);
  820.         break;
  821.     
  822.      case WACenter:        
  823.         tx = tPtr->offsetWidth + (tPtr->usableWidth - tw) / 2;
  824.         if (tw < tPtr->usableWidth)
  825.         XClearArea(screen->display, view->window, bd, bd,
  826.                totalWidth, view->size.height-2*bd, False);
  827.         break;
  828.  
  829.      default:
  830.      case WARight:
  831.         tx = tPtr->offsetWidth + tPtr->usableWidth - tw - 1;
  832.         if (tw < tPtr->usableWidth)
  833.         XClearArea(screen->display, view->window, bd, bd,
  834.                totalWidth-tw, view->size.height-2*bd, False);
  835.         break;
  836.     }
  837.  
  838.         if (!tPtr->flags.enabled)
  839.             WMSetColorInGC(screen->darkGray, screen->textFieldGC);
  840.  
  841.         WMDrawImageString(screen, drawbuffer, screen->textFieldGC,
  842.                           tPtr->font, tx, ty,
  843.                           &(text[tPtr->viewPosition]),
  844.                           tPtr->textLen - tPtr->viewPosition);
  845.  
  846.         if (tPtr->selection.count) {
  847.             int count,count2;
  848.  
  849.             count = tPtr->selection.count < 0
  850.                 ? tPtr->selection.position + tPtr->selection.count
  851.                 : tPtr->selection.position;
  852.             count2 = abs(tPtr->selection.count);
  853.             if (count < tPtr->viewPosition) {
  854.                 count2 = abs(count2 - abs(tPtr->viewPosition - count));
  855.                 count = tPtr->viewPosition;
  856.             }
  857.  
  858.  
  859.             rx = tPtr->offsetWidth + 1 + WMWidthOfString(tPtr->font,text,count)
  860.                 - WMWidthOfString(tPtr->font,text,tPtr->viewPosition);
  861.  
  862.             XSetBackground(screen->display, screen->textFieldGC,
  863.                     screen->gray->color.pixel);
  864.  
  865.             WMDrawImageString(screen, drawbuffer, screen->textFieldGC,
  866.                     tPtr->font, rx, ty, &(text[count]),
  867.                     count2);
  868.  
  869.             XSetBackground(screen->display, screen->textFieldGC,
  870.                     screen->white->color.pixel);
  871.         }
  872.  
  873.         if (!tPtr->flags.enabled)
  874.             WMSetColorInGC(screen->black, screen->textFieldGC);
  875.     } else {
  876.             XFillRectangle(screen->display, drawbuffer,
  877.                WMColorGC(screen->white),
  878.                bd,bd, totalWidth,view->size.height-2*bd);
  879.     }
  880.  
  881.     /* draw relief */
  882.     if (tPtr->flags.bordered) {
  883.         drawRelief(&viewbuffer, tPtr->flags.beveled);
  884.     }
  885.  
  886.     if (tPtr->flags.secure)
  887.         wfree(text);
  888.     XCopyArea(screen->display, drawbuffer, view->window,
  889.           screen->copyGC, 0,0, view->size.width,
  890.           view->size.height,0,0);
  891.     XFreePixmap(screen->display, drawbuffer);
  892.  
  893.     /* draw cursor */
  894.     if (tPtr->flags.focused && tPtr->flags.enabled && tPtr->flags.cursorOn) {
  895.         paintCursor(tPtr);
  896.     }
  897. }
  898.  
  899.  
  900. #if 0
  901. static void
  902. blinkCursor(void *data)
  903. {
  904.     TextField *tPtr = (TextField*)data;
  905.     
  906.     if (tPtr->flags.cursorOn) {
  907.     tPtr->timerID = WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY, blinkCursor,
  908.                       data);
  909.     } else {
  910.     tPtr->timerID = WMAddTimerHandler(CURSOR_BLINK_ON_DELAY, blinkCursor,
  911.                       data);    
  912.     }
  913.     paintCursor(tPtr);
  914.     tPtr->flags.cursorOn = !tPtr->flags.cursorOn;
  915. }
  916. #endif
  917.  
  918.  
  919. static void
  920. handleEvents(XEvent *event, void *data)
  921. {
  922.     TextField *tPtr = (TextField*)data;
  923.  
  924.     CHECK_CLASS(data, WC_TextField);
  925.  
  926.  
  927.     switch (event->type) {
  928.      case FocusIn:
  929.     if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr->view))!=tPtr->view)
  930.         return;
  931.     tPtr->flags.focused = 1;
  932. #if 0
  933.     if (!tPtr->timerID) {
  934.         tPtr->timerID = WMAddTimerHandler(CURSOR_BLINK_ON_DELAY, 
  935.                           blinkCursor, tPtr);
  936.     }
  937. #endif
  938.     paintTextField(tPtr);
  939.  
  940.     NOTIFY(tPtr, didBeginEditing, WMTextDidBeginEditingNotification, NULL);
  941.  
  942.     tPtr->flags.notIllegalMovement = 0;
  943.     break;
  944.  
  945.      case FocusOut:
  946.     tPtr->flags.focused = 0;
  947. #if 0
  948.     if (tPtr->timerID)
  949.         WMDeleteTimerHandler(tPtr->timerID);
  950.     tPtr->timerID = NULL;
  951. #endif
  952.  
  953.     paintTextField(tPtr);
  954.     if (!tPtr->flags.notIllegalMovement) {
  955.         NOTIFY(tPtr, didEndEditing, WMTextDidEndEditingNotification,
  956.            (void*)WMIllegalTextMovement);
  957.     }
  958.     break;
  959.  
  960.      case Expose:
  961.     if (event->xexpose.count!=0)
  962.         break;
  963.     paintTextField(tPtr);
  964.     break;
  965.     
  966.      case DestroyNotify:
  967.     destroyTextField(tPtr);
  968.     break;
  969.     }
  970. }
  971.  
  972.  
  973. static void
  974. handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
  975. {
  976.     char buffer[64];
  977.     KeySym ksym;
  978.     char *textEvent = NULL;
  979.     void *data = NULL;
  980.     int count, refresh = 0;
  981.     int control_pressed = 0;
  982.     int cancelSelection = 1;
  983.  
  984.     /*printf("(%d,%d) -> ", tPtr->selection.position, tPtr->selection.count);*/
  985.     if (((XKeyEvent *) event)->state & WM_EMACSKEYMASK)
  986.     control_pressed = 1;
  987.  
  988.     count = XLookupString(&event->xkey, buffer, 63, &ksym, NULL);
  989.     buffer[count] = '\0';
  990.  
  991.     switch (ksym) {
  992.      case XK_Tab:
  993. #ifdef XK_ISO_Left_Tab
  994.      case XK_ISO_Left_Tab:
  995. #endif
  996.     if (event->xkey.state & ShiftMask) {
  997.         if (tPtr->view->prevFocusChain) {
  998.         W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr->view),
  999.                      tPtr->view->prevFocusChain);
  1000.         tPtr->flags.notIllegalMovement = 1;
  1001.             }
  1002.             data = (void*)WMBacktabTextMovement;
  1003.     } else {
  1004.         if (tPtr->view->nextFocusChain) {
  1005.         W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr->view),
  1006.                      tPtr->view->nextFocusChain);
  1007.         tPtr->flags.notIllegalMovement = 1;
  1008.             }
  1009.             data = (void*)WMTabTextMovement;
  1010.     }
  1011.         textEvent = WMTextDidEndEditingNotification;
  1012.     break;
  1013.  
  1014.      case XK_Return:
  1015.         data = (void*)WMReturnTextMovement;
  1016.         textEvent = WMTextDidEndEditingNotification;
  1017.     break;
  1018.  
  1019.      case WM_EMACSKEY_LEFT:
  1020.     if (!control_pressed) {
  1021.         goto normal_key;
  1022.     }
  1023. #ifdef XK_KP_Left
  1024.      case XK_KP_Left:
  1025. #endif
  1026.      case XK_Left:
  1027.     if (tPtr->cursorPosition > 0) {
  1028.         paintCursor(tPtr);
  1029.             if (event->xkey.state & ControlMask) {
  1030.                 int i = tPtr->cursorPosition - 1;
  1031.                 
  1032.         while (i > 0 && tPtr->text[i] != ' ') i--;
  1033.         while (i > 0 && tPtr->text[i] == ' ') i--;
  1034.  
  1035.         tPtr->cursorPosition = (i > 0) ? i + 1 : 0;
  1036.             } else
  1037.         tPtr->cursorPosition--;
  1038.  
  1039.         if (tPtr->cursorPosition < tPtr->viewPosition) {
  1040.         tPtr->viewPosition = tPtr->cursorPosition;
  1041.         refresh = 1;
  1042.         } else
  1043.         paintCursor(tPtr);
  1044.     }
  1045.     if (event->xkey.state & ShiftMask)
  1046.         cancelSelection = 0;
  1047.     break;
  1048.  
  1049.     case WM_EMACSKEY_RIGHT:
  1050.         if (!control_pressed) {
  1051.             goto normal_key;
  1052.         }
  1053. #ifdef XK_KP_Right
  1054.     case XK_KP_Right:
  1055. #endif
  1056.     case XK_Right:
  1057.     if (tPtr->cursorPosition < tPtr->textLen) {
  1058.         paintCursor(tPtr);
  1059.             if (event->xkey.state & ControlMask) {
  1060.                 int i = tPtr->cursorPosition;
  1061.                 
  1062.                 while (tPtr->text[i] && tPtr->text[i] != ' ') i++;
  1063.                 while (tPtr->text[i] == ' ') i++;
  1064.  
  1065.                 tPtr->cursorPosition = i;
  1066.             } else {
  1067.                tPtr->cursorPosition++;
  1068.             }
  1069.         while (WMWidthOfString(tPtr->font,
  1070.                 &(tPtr->text[tPtr->viewPosition]),
  1071.                 tPtr->cursorPosition-tPtr->viewPosition)
  1072.            > tPtr->usableWidth) {
  1073.         tPtr->viewPosition++;
  1074.         refresh = 1;
  1075.         }
  1076.         if (!refresh)
  1077.         paintCursor(tPtr);
  1078.     }
  1079.     if (event->xkey.state & ShiftMask)
  1080.         cancelSelection = 0;
  1081.     break;
  1082.     
  1083.     case WM_EMACSKEY_HOME:
  1084.         if (!control_pressed) {
  1085.             goto normal_key;
  1086.         }
  1087. #ifdef XK_KP_Home
  1088.     case XK_KP_Home:
  1089. #endif
  1090.     case XK_Home:
  1091.     if (tPtr->cursorPosition > 0) {
  1092.         paintCursor(tPtr);
  1093.         tPtr->cursorPosition = 0;
  1094.         if (tPtr->viewPosition > 0) {
  1095.         tPtr->viewPosition = 0;
  1096.         refresh = 1;
  1097.         } else
  1098.         paintCursor(tPtr);
  1099.     }
  1100.     if (event->xkey.state & ShiftMask)
  1101.         cancelSelection = 0;
  1102.     break;
  1103.     
  1104.     case WM_EMACSKEY_END:
  1105.         if (!control_pressed) {
  1106.             goto normal_key;
  1107.         }
  1108. #ifdef XK_KP_End
  1109.     case XK_KP_End:
  1110. #endif
  1111.     case XK_End:
  1112.     if (tPtr->cursorPosition < tPtr->textLen) {
  1113.         paintCursor(tPtr);
  1114.         tPtr->cursorPosition = tPtr->textLen;
  1115.         tPtr->viewPosition = 0;
  1116.         while (WMWidthOfString(tPtr->font,
  1117.                    &(tPtr->text[tPtr->viewPosition]),
  1118.                    tPtr->textLen-tPtr->viewPosition)
  1119.            > tPtr->usableWidth) {
  1120.         tPtr->viewPosition++;
  1121.         refresh = 1;
  1122.         }
  1123.         if (!refresh)
  1124.         paintCursor(tPtr);
  1125.     }
  1126.     if (event->xkey.state & ShiftMask)
  1127.         cancelSelection = 0;
  1128.     break;
  1129.     
  1130.      case WM_EMACSKEY_BS:
  1131.          if (!control_pressed) {
  1132.              goto normal_key;
  1133.          }
  1134.      case XK_BackSpace:
  1135.          if (tPtr->selection.count) {
  1136.         WMDeleteTextFieldRange(tPtr, tPtr->selection);
  1137.             data = (void*)WMDeleteTextEvent;
  1138.             textEvent = WMTextDidChangeNotification;
  1139.     } else if (tPtr->cursorPosition > 0) {
  1140.             WMRange range;
  1141.             range.position = tPtr->cursorPosition - 1;
  1142.             range.count = 1;
  1143.         WMDeleteTextFieldRange(tPtr, range);
  1144.             data = (void*)WMDeleteTextEvent;
  1145.             textEvent = WMTextDidChangeNotification;
  1146.     }
  1147.     break;
  1148.     
  1149.     case WM_EMACSKEY_DEL:
  1150.         if (!control_pressed) {
  1151.             goto normal_key;
  1152.         }
  1153. #ifdef XK_KP_Delete
  1154.     case XK_KP_Delete:
  1155. #endif
  1156.     case XK_Delete:
  1157.          if (tPtr->selection.count) {
  1158.         WMDeleteTextFieldRange(tPtr, tPtr->selection);
  1159.             data = (void*)WMDeleteTextEvent;
  1160.             textEvent = WMTextDidChangeNotification;
  1161.     } else if (tPtr->cursorPosition < tPtr->textLen) {
  1162.             WMRange range;
  1163.             range.position = tPtr->cursorPosition;
  1164.             range.count = 1;
  1165.         WMDeleteTextFieldRange(tPtr, range);
  1166.             data = (void*)WMDeleteTextEvent;
  1167.             textEvent = WMTextDidChangeNotification;
  1168.         }
  1169.     break;
  1170.  
  1171.     normal_key:
  1172.      default:
  1173.     if (count > 0 && isprint(buffer[0])) {
  1174.             if (tPtr->selection.count)
  1175.                 WMDeleteTextFieldRange(tPtr, tPtr->selection);
  1176.         WMInsertTextFieldText(tPtr, buffer, tPtr->cursorPosition);
  1177.             data = (void*)WMInsertTextEvent;
  1178.             textEvent = WMTextDidChangeNotification;
  1179.         } else {
  1180.             /* should we rather break and goto cancel selection below? -Dan */
  1181.             return;
  1182.         }
  1183.     break;
  1184.     }
  1185.  
  1186.     if (!cancelSelection) {
  1187.         if (tPtr->selection.count != tPtr->cursorPosition - tPtr->selection.position) {
  1188.         WMNotification *notif;
  1189.         
  1190.             tPtr->selection.count = tPtr->cursorPosition - tPtr->selection.position;
  1191.  
  1192.             XSetSelectionOwner(tPtr->view->screen->display,
  1193.                                XA_PRIMARY, tPtr->view->window,
  1194.                    event->xbutton.time);
  1195.             notif = WMCreateNotification("_lostOwnership", NULL, tPtr);
  1196.             WMPostNotification(notif);
  1197.             WMReleaseNotification(notif);
  1198.  
  1199.             refresh = 1;
  1200.         }
  1201.     } else {
  1202.         if (tPtr->selection.count) {
  1203.             tPtr->selection.count = 0;
  1204.             refresh = 1;
  1205.     }
  1206.         tPtr->selection.position = tPtr->cursorPosition;
  1207.     }
  1208.  
  1209.     /*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count);*/
  1210.  
  1211.     if (textEvent) {
  1212.         WMNotification *notif = WMCreateNotification(textEvent, tPtr, data);
  1213.  
  1214.         if (tPtr->delegate) {
  1215.             if (textEvent==WMTextDidBeginEditingNotification &&
  1216.                 tPtr->delegate->didBeginEditing)
  1217.                 (*tPtr->delegate->didBeginEditing)(tPtr->delegate, notif);
  1218.             else if (textEvent==WMTextDidEndEditingNotification &&
  1219.                      tPtr->delegate->didEndEditing)
  1220.                 (*tPtr->delegate->didEndEditing)(tPtr->delegate, notif);
  1221.             else if (textEvent==WMTextDidChangeNotification &&
  1222.                      tPtr->delegate->didChange)
  1223.                 (*tPtr->delegate->didChange)(tPtr->delegate, notif);
  1224.         }
  1225.  
  1226.         WMPostNotification(notif);
  1227.         WMReleaseNotification(notif);
  1228.     }
  1229.  
  1230.     if (refresh)
  1231.     paintTextField(tPtr);
  1232.  
  1233.     /*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count);*/
  1234. }
  1235.  
  1236.  
  1237. static int
  1238. pointToCursorPosition(TextField *tPtr, int x)
  1239. {
  1240.     int a, b, mid;
  1241.     int tw;
  1242.  
  1243.     if (tPtr->flags.bordered)
  1244.     x -= 2;
  1245.  
  1246.     a = tPtr->viewPosition;
  1247.     b = tPtr->viewPosition + tPtr->textLen;
  1248.     if (WMWidthOfString(tPtr->font, &(tPtr->text[tPtr->viewPosition]), 
  1249.             tPtr->textLen - tPtr->viewPosition) < x)
  1250.     return tPtr->textLen;
  1251.  
  1252.     while (a < b && b-a>1) {
  1253.     mid = (a+b)/2;
  1254.     tw = WMWidthOfString(tPtr->font, &(tPtr->text[tPtr->viewPosition]), 
  1255.                  mid - tPtr->viewPosition);
  1256.     if (tw > x)
  1257.         b = mid;
  1258.     else if (tw < x)
  1259.         a = mid;
  1260.     else
  1261.         return mid;
  1262.     }
  1263.     return (a+b)/2;
  1264. }
  1265.  
  1266.  
  1267. static void
  1268. handleTextFieldActionEvents(XEvent *event, void *data)
  1269. {
  1270.     TextField *tPtr = (TextField*)data;
  1271.     static int move = 0;
  1272.     static Time lastButtonReleasedEvent = 0;
  1273.     
  1274.     CHECK_CLASS(data, WC_TextField);
  1275.  
  1276.     switch (event->type) {
  1277.      case KeyPress:
  1278.         if (tPtr->flags.enabled && tPtr->flags.focused) {
  1279.             handleTextFieldKeyPress(tPtr, event);
  1280.         XGrabPointer(WMScreenDisplay(W_VIEW(tPtr)->screen),
  1281.              W_VIEW(tPtr)->window, False, 
  1282.              PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
  1283.              GrabModeAsync, GrabModeAsync, None, 
  1284.              W_VIEW(tPtr)->screen->invisibleCursor,
  1285.              CurrentTime);
  1286.         tPtr->flags.pointerGrabbed = 1;
  1287.     }
  1288.         break;
  1289.  
  1290.      case MotionNotify:
  1291.     
  1292.     if (tPtr->flags.pointerGrabbed) {
  1293.         tPtr->flags.pointerGrabbed = 0;
  1294.         XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr)->screen), CurrentTime);
  1295.     }
  1296.  
  1297.         if (tPtr->flags.enabled && (event->xmotion.state & Button1Mask)) {
  1298.  
  1299.         if (tPtr->viewPosition < tPtr->textLen && event->xmotion.x >
  1300.                 tPtr->usableWidth) {
  1301.         if (WMWidthOfString(tPtr->font,
  1302.                     &(tPtr->text[tPtr->viewPosition]),
  1303.                     tPtr->cursorPosition-tPtr->viewPosition)
  1304.                     > tPtr->usableWidth) {
  1305.             tPtr->viewPosition++;
  1306.         }
  1307.         } else if (tPtr->viewPosition > 0 && event->xmotion.x < 0) {
  1308.         paintCursor(tPtr);
  1309.         tPtr->viewPosition--;
  1310.         }
  1311.  
  1312.         /*if (!tPtr->selection.count) {
  1313.         tPtr->selection.position = tPtr->cursorPosition;
  1314.         }*/
  1315.         
  1316.         tPtr->cursorPosition = 
  1317.         pointToCursorPosition(tPtr, event->xmotion.x);
  1318.         
  1319.         tPtr->selection.count = tPtr->cursorPosition - tPtr->selection.position;
  1320.         /*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count);*/
  1321.         
  1322.         /*
  1323.          printf("notify %d %d\n",event->xmotion.x,tPtr->usableWidth);
  1324.          */
  1325.         
  1326.         paintCursor(tPtr);
  1327.         paintTextField(tPtr);
  1328.  
  1329.     }
  1330.         if (move) {
  1331.             XSetSelectionOwner(tPtr->view->screen->display,
  1332.                        XA_PRIMARY, tPtr->view->window,  event->xmotion.time);
  1333.             {
  1334.                 WMNotification *notif = WMCreateNotification("_lostOwnership",
  1335.                         NULL,tPtr);
  1336.                 WMPostNotification(notif);
  1337.                 WMReleaseNotification(notif);
  1338.             }
  1339.         }
  1340.     break;
  1341.  
  1342.      case ButtonPress:
  1343.     if (tPtr->flags.pointerGrabbed) {
  1344.         tPtr->flags.pointerGrabbed = 0;
  1345.         XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr)->screen), CurrentTime);
  1346.         break;
  1347.     }
  1348.  
  1349.         move = 1;
  1350.         switch (tPtr->flags.alignment) {
  1351.             int textWidth;
  1352.          case WARight:
  1353.             textWidth = WMWidthOfString(tPtr->font, tPtr->text, tPtr->textLen);
  1354.             if (tPtr->flags.enabled && !tPtr->flags.focused) {
  1355.                 WMSetFocusToWidget(tPtr);
  1356.             } else if (tPtr->flags.focused) {
  1357.         tPtr->selection.position = tPtr->cursorPosition;
  1358.                 tPtr->selection.count = 0;
  1359.             }
  1360.             if(textWidth < tPtr->usableWidth){
  1361.                 tPtr->cursorPosition = pointToCursorPosition(tPtr, 
  1362.                      event->xbutton.x - tPtr->usableWidth
  1363.                                      + textWidth);
  1364.             }
  1365.             else tPtr->cursorPosition = pointToCursorPosition(tPtr, 
  1366.                                      event->xbutton.x);
  1367.             /*
  1368.             tPtr->cursorPosition = pointToCursorPosition(tPtr, 
  1369.                                      event->xbutton.x);
  1370.                 tPtr->cursorPosition += tPtr->usableWidth - textWidth;
  1371.             }
  1372.  
  1373.             tPtr->cursorPosition = pointToCursorPosition(tPtr, 
  1374.                                      event->xbutton.x);
  1375.                                      */
  1376.             paintTextField(tPtr);
  1377.             break;
  1378.         
  1379.          case WALeft:
  1380.             if (tPtr->flags.enabled && !tPtr->flags.focused) {
  1381.                 WMSetFocusToWidget(tPtr);
  1382.                 tPtr->cursorPosition = pointToCursorPosition(tPtr, 
  1383.                                      event->xbutton.x);
  1384.                 paintTextField(tPtr);
  1385.             } else if (tPtr->flags.focused) {
  1386.                 tPtr->cursorPosition = pointToCursorPosition(tPtr, 
  1387.                                      event->xbutton.x);
  1388.         tPtr->selection.position = tPtr->cursorPosition;
  1389.                 tPtr->selection.count = 0;
  1390.                 paintTextField(tPtr);
  1391.             }
  1392.             if (event->xbutton.button == Button2 && tPtr->flags.enabled) {
  1393.                 char *text;
  1394.  
  1395.                 text = W_GetTextSelection(tPtr->view->screen, XA_PRIMARY);
  1396.                 
  1397.                 if (!text) {
  1398.                     text = W_GetTextSelection(tPtr->view->screen,
  1399.                               tPtr->view->screen->clipboardAtom);
  1400.                 }
  1401.                 if (!text) {
  1402.             text = W_GetTextSelection(tPtr->view->screen, 
  1403.                           XA_CUT_BUFFER0);
  1404.                 }
  1405.                 if (text) {
  1406.             WMInsertTextFieldText(tPtr, text, tPtr->cursorPosition);
  1407.             XFree(text);
  1408.                     NOTIFY(tPtr, didChange, WMTextDidChangeNotification,
  1409.                            (void*)WMInsertTextEvent);
  1410.                 }
  1411.             }
  1412.             break;
  1413.         }
  1414.     break;
  1415.  
  1416.     case ButtonRelease:
  1417.         if (tPtr->flags.pointerGrabbed) {
  1418.             tPtr->flags.pointerGrabbed = 0;
  1419.             XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr)->screen), CurrentTime);
  1420.         }
  1421.  
  1422.             move = 0;
  1423.         
  1424.         if (event->xbutton.time - lastButtonReleasedEvent
  1425.             <= WINGsConfiguration.doubleClickDelay) {
  1426.             tPtr->selection.position = 0;
  1427.             tPtr->selection.count = tPtr->textLen;
  1428.             paintTextField(tPtr);
  1429.                 XSetSelectionOwner(tPtr->view->screen->display,
  1430.                        XA_PRIMARY, tPtr->view->window,  event->xbutton.time);
  1431.                 {
  1432.                     WMNotification *notif = WMCreateNotification("_lostOwnership",
  1433.                         NULL,tPtr);
  1434.                     WMPostNotification(notif);
  1435.                     WMReleaseNotification(notif);
  1436.                 }
  1437.         }
  1438.         lastButtonReleasedEvent = event->xbutton.time;
  1439.         
  1440.         break;
  1441.     }
  1442. }
  1443.  
  1444.  
  1445. static void
  1446. destroyTextField(TextField *tPtr)
  1447. {
  1448. #if 0
  1449.     if (tPtr->timerID)
  1450.     WMDeleteTimerHandler(tPtr->timerID);
  1451. #endif
  1452.  
  1453.     WMReleaseFont(tPtr->font);
  1454.     WMDeleteSelectionHandler(tPtr, XA_PRIMARY);
  1455.     WMRemoveNotificationObserver(tPtr);
  1456.  
  1457.     if (tPtr->text)
  1458.     wfree(tPtr->text);
  1459.  
  1460.     wfree(tPtr);
  1461. }
  1462.